<template>
  <div class="file-upload">
    <el-upload
      ref="uploadRef"
      :class="uploadClass"
      :action="uploadAction"
      :headers="uploadHeaders"
      :data="uploadData"
      :multiple="multiple"
      :accept="accept"
      :show-file-list="showFileList"
      :auto-upload="autoUpload"
      :drag="drag"
      :before-upload="handleBeforeUpload"
      :on-success="handleSuccess"
      :on-error="handleError"
      :on-progress="handleProgress"
      :on-change="handleChange"
      :on-remove="handleRemove"
      v-bind="$attrs"
    >
      <slot>
        <div v-if="type === 'image'" class="image-upload-area">
          <img v-if="imageUrl" :src="imageUrl" class="uploaded-image" />
          <div v-else class="upload-placeholder">
            <el-icon class="upload-icon"><Plus /></el-icon>
            <div class="upload-text">{{ uploadText || '点击上传图片' }}</div>
            <div class="upload-tip">{{ uploadTip }}</div>
          </div>
        </div>
        
        <div v-else-if="drag" class="drag-upload-area">
          <el-icon class="upload-icon"><Upload /></el-icon>
          <div class="upload-text">{{ uploadText || '将文件拖拽到此处，或点击上传' }}</div>
          <div class="upload-tip">{{ uploadTip }}</div>
        </div>
        
        <el-button v-else type="primary" :loading="uploading">
          <el-icon><Upload /></el-icon>
          {{ uploading ? '上传中...' : (uploadText || '选择文件') }}
        </el-button>
      </slot>
      
      <template #tip v-if="showTip">
        <div class="el-upload__tip">{{ uploadTip }}</div>
      </template>
    </el-upload>
    
    <!-- 图片预览对话框 -->
    <el-dialog v-model="previewVisible" title="图片预览" width="800px">
      <img :src="previewUrl" alt="预览图片" style="width: 100%; height: auto;" />
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { ElMessage, type UploadInstance } from 'element-plus'
import { Plus, Upload } from '@element-plus/icons-vue'
import { 
  validateFile, 
  formatFileSize, 
  FILE_SIZE_LIMITS,
  SUPPORTED_FILE_TYPES,
  type FileValidationOptions 
} from '@/config/upload'

interface Props {
  // 基础配置
  type?: 'image' | 'file' | 'document' | 'video' | 'audio'
  modelValue?: string | string[]
  multiple?: boolean
  accept?: string
  maxSize?: number // MB
  
  // 上传配置
  action?: string
  headers?: Record<string, string>
  data?: Record<string, any>
  autoUpload?: boolean
  
  // UI配置
  drag?: boolean
  showFileList?: boolean
  showTip?: boolean
  uploadText?: string
  uploadTip?: string
  
  // 样式配置
  width?: string
  height?: string
  
  // 验证配置
  allowedTypes?: string[]
  customValidation?: (file: File) => { valid: boolean; error?: string }
}

const props = withDefaults(defineProps<Props>(), {
  type: 'file',
  multiple: false,
  autoUpload: true,
  drag: false,
  showFileList: true,
  showTip: true,
  action: '/admin/attachment/upload',
  width: '100%',
  height: 'auto'
})

const emit = defineEmits<{
  'update:modelValue': [value: string | string[]]
  'success': [response: any, file: File]
  'error': [error: any, file: File]
  'progress': [event: any, file: File]
  'change': [file: any, fileList: any[]]
  'remove': [file: any, fileList: any[]]
}>()

// 响应式数据
const uploadRef = ref<UploadInstance>()
const uploading = ref(false)
const previewVisible = ref(false)
const previewUrl = ref('')

// 计算属性
const imageUrl = computed(() => {
  if (props.type === 'image' && typeof props.modelValue === 'string') {
    return props.modelValue
  }
  return ''
})

const uploadClass = computed(() => {
  const classes = ['file-upload-component']
  if (props.type === 'image') classes.push('image-uploader')
  if (props.drag) classes.push('drag-uploader')
  return classes.join(' ')
})

const uploadAction = computed(() => props.action)

const uploadHeaders = computed(() => {
  const token = localStorage.getItem('token')
  return {
    'Authorization': token ? `Bearer ${token}` : '',
    ...props.headers
  }
})

const uploadData = computed(() => props.data || {})

const accept = computed(() => {
  if (props.accept) return props.accept
  
  switch (props.type) {
    case 'image':
      return 'image/*'
    case 'document':
      return '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.csv'
    case 'video':
      return 'video/*'
    case 'audio':
      return 'audio/*'
    default:
      return '*'
  }
})

const uploadTip = computed(() => {
  if (props.uploadTip) return props.uploadTip
  
  const maxSize = props.maxSize || FILE_SIZE_LIMITS[props.type.toUpperCase() as keyof typeof FILE_SIZE_LIMITS] || FILE_SIZE_LIMITS.GENERAL
  
  switch (props.type) {
    case 'image':
      return `支持 JPG、PNG、GIF、WebP 格式，最大 ${maxSize}MB`
    case 'document':
      return `支持 PDF、Word、Excel、PPT 等格式，最大 ${maxSize}MB`
    case 'video':
      return `支持 MP4、AVI、MOV 等格式，最大 ${maxSize}MB`
    case 'audio':
      return `支持 MP3、WAV、OGG 等格式，最大 ${maxSize}MB`
    default:
      return `文件大小不超过 ${maxSize}MB`
  }
})

// 方法
const handleBeforeUpload = (file: File) => {
  // 自定义验证
  if (props.customValidation) {
    const result = props.customValidation(file)
    if (!result.valid) {
      ElMessage.error(result.error || '文件验证失败')
      return false
    }
  }
  
  // 使用统一验证
  const validationOptions: FileValidationOptions = {}
  
  if (props.allowedTypes) {
    validationOptions.allowedTypes = props.allowedTypes
  } else if (props.type !== 'file') {
    validationOptions.category = props.type.toUpperCase() as keyof typeof SUPPORTED_FILE_TYPES
  }
  
  if (props.maxSize) {
    validationOptions.maxSizeMB = props.maxSize
  }
  
  const validation = validateFile(file, validationOptions)
  if (!validation.valid) {
    ElMessage.error(validation.error!)
    return false
  }
  
  uploading.value = true
  return true
}

const handleSuccess = (response: any, file: File) => {
  uploading.value = false

  // 处理不同的响应格式
  let fileUrl = ''
  if (response && response.data && response.data.url) {
    // 标准的API响应格式：{ code: 0, data: { url: "..." } }
    fileUrl = response.data.url
  } else if (response && response.url) {
    // 直接的URL响应格式：{ url: "..." }
    fileUrl = response.url
  }

  if (fileUrl) {
    const newValue = props.multiple
      ? [...(Array.isArray(props.modelValue) ? props.modelValue : []), fileUrl]
      : fileUrl

    emit('update:modelValue', newValue)
    emit('success', response, file)
    ElMessage.success('文件上传成功')
  } else {
    console.error('上传响应格式错误:', response)
    ElMessage.error('上传失败：未获取到文件URL')
  }
}

const handleError = (error: any, file: File) => {
  uploading.value = false
  emit('error', error, file)
  ElMessage.error('文件上传失败')
}

const handleProgress = (event: any, file: File) => {
  emit('progress', event, file)
}

const handleChange = (file: any, fileList: any[]) => {
  emit('change', file, fileList)
}

const handleRemove = (file: any, fileList: any[]) => {
  emit('remove', file, fileList)
}

// 预览图片
const previewImage = (url: string) => {
  previewUrl.value = url
  previewVisible.value = true
}

// 清空文件
const clearFiles = () => {
  uploadRef.value?.clearFiles()
  emit('update:modelValue', props.multiple ? [] : '')
}

// 暴露方法
defineExpose({
  clearFiles,
  previewImage,
  uploadRef
})
</script>

<style scoped lang="scss">
.file-upload {
  width: 100%;
  
  .image-upload-area {
    width: 178px;
    height: 178px;
    border: 2px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: border-color 0.3s;
    
    &:hover {
      border-color: #409eff;
    }
    
    .uploaded-image {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
    
    .upload-placeholder {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      height: 100%;
      text-align: center;
      color: #8c939d;
      
      .upload-icon {
        font-size: 28px;
        margin-bottom: 8px;
      }
      
      .upload-text {
        font-size: 14px;
        margin-bottom: 4px;
      }
      
      .upload-tip {
        font-size: 12px;
        color: #999;
        padding: 0 8px;
      }
    }
  }
  
  .drag-upload-area {
    text-align: center;
    padding: 40px 20px;
    color: #8c939d;
    
    .upload-icon {
      font-size: 48px;
      margin-bottom: 16px;
    }
    
    .upload-text {
      font-size: 16px;
      margin-bottom: 8px;
    }
    
    .upload-tip {
      font-size: 14px;
      color: #999;
    }
  }
}

:deep(.el-upload) {
  width: 100%;
}

:deep(.el-upload-dragger) {
  width: 100%;
  height: auto;
  min-height: 180px;
}
</style>
